package org.voidness.squaretilesframework;

import org.voidness.squaretilesframework.sprites.GLSprite;

/** A class to represent a square tile map */
public class Map {
    /** The tile information for the map */
    private Tile[][] tiles = null;

    /** The name of the map */
    protected String name = null;

    /** The size of the tiles */
    protected int tileSize;

    /** The width of the map */
    protected int widthInTiles;

    /** The height of the map */
    protected int heightInTiles;

    /** The map's tile set */
    private TileSet tileSet = null;

    /** The map's object set */
    private ObjectTileSet objectTileSet = null;

    /** No direction (actor movement) */
    public static final int NONE = 0;

    /** North direction (actor movement) */
    public static final int NORTH = 8;

    /** South direction (actor movement) */
    public static final int SOUTH = 2;

    /** East direction (actor movement) */
    public static final int EAST = 6;

    /** West direction (actor movement) */
    public static final int WEST = 4;

    /** Northwest direction (actor movement) */
    public static final int NORTHWEST = 7;

    /** Northeast direction (actor movement) */
    public static final int NORTHEAST = 9;

    /** Southwest direction (actor movement) */
    public static final int SOUTHWEST = 1;

    /** Southeast direction (actor movement) */
    public static final int SOUTHEAST = 3;

    /**
     * The default map constructor.
     * 
     * @param mName The name of the map
     * @param mTiles The tile information for the map
     * @param mTileSet The tileset for the map
     * @param mObjectTileSet The objectset for the map
     */
    public Map(String mName, Tile[][] mTiles, TileSet mTileSet,
            ObjectTileSet mObjectTileSet) {
        name = mName;
        tiles = mTiles;
        tileSet = mTileSet;
        objectTileSet = mObjectTileSet;

        // Number of tiles in the map (both in x and y)
        widthInTiles = tiles.length; // horizontal
        heightInTiles = tiles[0].length; // vertical
    }

    /**
     * Another constructor. This one builds an empty map
     * 
     * @param mWidth The width of the new map
     * @param mHeight The height of the new map
     */
    public Map(int mWidth, int mHeight) {
        name = new String("untitled");
        widthInTiles = mWidth;
        heightInTiles = mHeight;
        tileSet = new TileSet();
        objectTileSet = new ObjectTileSet();
        tiles = initializeTiles(mWidth, mHeight);
    }

    /**
     * (Re)initializes the map's tiles
     * 
     * @param mWidth The width of the map
     * @param mHeight The height of the map
     * @return The newly generated tile array
     */
    private Tile[][] initializeTiles(int mWidth, int mHeight) {
        Tile[][] tiles = new Tile[mWidth][mHeight];
        for (int i = 0; i < mWidth; i++)
            for (int j = 0; j < mHeight; j++)
                tiles[i][j] = new Tile(-1, -1, this, true);
        return tiles;
    }

    /**
     * (Re)defines the map's name
     * 
     * @param mName The new name to set
     */
    public void setName(String mName) {
        name = mName;
    }

    /**
     * Returns the map's name
     * 
     * @return A string with the map name
     */
    public String getName() {
        return name;
    }

    /**
     * (Re)defines the map's tiles
     * 
     * @param mTiles The new tiles to set
     */
    public void setTiles(Tile[][] mTiles) {
        tiles = mTiles;

        // Number of tiles in the map (both in x and y)
        widthInTiles = tiles.length; // horizontal
        heightInTiles = tiles[0].length; // vertical
    }

    /**
     * (Re)defines the map's tile set
     * 
     * @param mTileSet The new tileset to set
     */
    public void setTileSet(TileSet mTileSet) {
        tileSet = mTileSet;
    }

    /**
     * Returns the map's tile set
     * 
     * @return The map's TileSet
     */
    public TileSet getTileSet() {
        return tileSet;
    }

    /**
     * (Re)defines the map's object set
     * 
     * @param mObjectTileSet The new objectset to set
     */
    public void setObjectTileSet(ObjectTileSet mObjectTileSet) {
        objectTileSet = mObjectTileSet;
    }

    /**
     * Returns the map's object set
     * 
     * @return The map's ObjectTileSet
     */
    public ObjectTileSet getObjectTileSet() {
        return objectTileSet;
    }

    /**
     * Defines the tile size.
     * 
     * @param mTileSize The new size to use
     */
    public void setTileSize(int mTileSize) {
        tileSize = mTileSize;
    }

    /**
     * Get the width of the map (in tiles).
     * 
     * @return The width of the map
     */
    public int getWidth() {
        return widthInTiles;
    }

    /**
     * Get the height of the map (in tiles).
     * 
     * @return The height of the map
     */
    public int getHeight() {
        return heightInTiles;
    }

    /**
     * Get the tile at mX,mY.
     * 
     * @param mX The X index of the tile to get
     * @param mY The Y index of the tile to get
     * @return The tile at mX,mY
     */
    public Tile tileAt(int mX, int mY) {
        return tiles[mX][mY];
    }

    /**
     * Get the size of the tiles (in pixels).
     * 
     * @return The tile size
     */
    public int getTileSize() {
        return tileSize;
    }

    /**
     * (Re)defines a map tile's occupation
     * 
     * @param mI The tile's position in the map
     * @param mJ The tile's position in the map
     * @param mOccupier The occupier to set
     */
    public void setTileOccupier(int mI, int mJ, GLSprite mOccupier) {
        tiles[mI][mJ].setOccupier(mOccupier);
    }

    /**
     * (Re)defines a map tile's object occupation
     * 
     * @param mI The tile's position in the map
     * @param mJ The tile's position in the map
     * @param mObjectIndex The occupier to set
     */
    public void setObjectIndex(int mI, int mJ, int mObjectIndex) {
        tiles[mI][mJ].setObjectIndex(mObjectIndex);
    }

    /**
     * Clones a map.
     * 
     * @return A new map
     */
    public Object clone() {
        return new Map(name, (Tile[][]) tiles.clone(), tileSet, objectTileSet);
    }
}